﻿using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using DimensionsHelper.LanguageService.Syntax;

namespace DimensionsHelper.LanguageService;

public partial class Parser
{
    private const string IdentifierName = "标识符";
    private const string ExpressionName = "表达式";

    private readonly Stack<Statement> _blockStack;
    private readonly DiagnosticStorage _diagnostics;
    private readonly int _length;
    private readonly SourceNodeList _nodes;
    private readonly SourceTextFile _source;

    private readonly SyntaxTree _tree;

    private readonly Stack<WithStatement> _withStack;

    private EventSection? _eventSection;
    private SectionStatement? _section;
    private ParserState _state;

    private Parser(SourceTextFile src, SyntaxTree? entry)
    {
        _source = src;
        _tree = new SyntaxTree(src, entry);
        _diagnostics = _tree.GetDiagnosticStorage();
        _source.Preprocessed ??= Preprocessor.Process(_source);
        _nodes = _source.Preprocessed.NodeListInternal;
        _length = _source.Preprocessed.Count;
        _withStack = new Stack<WithStatement>();
        _blockStack = new Stack<Statement>();
        _state = new ParserState
        {
            ExpansionIndex = -1,
            Index = -1
        };
        // 文件类型以预处理结果为准，因为允许使用注释指令更改文件类型。
        _state.SetKeywordContexts(GetSourceFileKeywordContexts(src));
        _state.SetPunctuationContexts(GetSourceFilePunctuationContexts(src));
    }


    private static KeywordContexts GetSourceFileKeywordContexts(SourceTextFile src)
    {
        return src.Preprocessed!.FileType switch
        {
            SourceFileType.Dms => KeywordContexts.Dms,
            SourceFileType.Declare => KeywordContexts.Declaration,
            SourceFileType.Metadata => KeywordContexts.Metadata,
            _ => KeywordContexts.Mrs
        };
    }


    private static PunctuationContexts GetSourceFilePunctuationContexts(SourceTextFile src)
    {
        return src.Preprocessed!.FileType switch
        {
            SourceFileType.Metadata => PunctuationContexts.Metadata,
            _ => PunctuationContexts.Script
        };
    }


    private SyntaxTreeParseContext GetSyntaxTreeParseContext()
    {
        return new SyntaxTreeParseContext
        {
            IsOptionImplicit = _state.IsOptionImplicit,
            IsOptionGlobalVariables = _state.IsOptionGlobalVariables,
            ContainingNode = _blockStack.TryPeek(out Statement? containingBlock)
                ? new WeakReference<Statement>(containingBlock)
                : null,
            Index = -1, // ParseTree 方法会先调用一次 Next() 方法，因此，此处需要预留一个索引位置。
            KeywordContexts = _state.KeywordContexts,
            PunctuationContexts = _state.PunctuationContexts,
            ContainingWithStatement = _withStack.TryPeek(out WithStatement? containingWithStat)
                ? new WeakReference<WithStatement>(containingWithStat)
                : null,
            IgnoreTypeError = _state.IgnoreTypeError,
            ContainingEventSection = _eventSection != null
                ? new WeakReference<EventSection>(_eventSection)
                : null,
            ContainingSection = _section != null
                ? new WeakReference<SectionStatement>(_section)
                : null
        };
    }


    private void SetSyntaxTreeParseContext(SyntaxTreeParseContext context)
    {
        _state.IsOptionImplicit = context.IsOptionImplicit;
        _state.IsOptionGlobalVariables = context.IsOptionGlobalVariables;
        _state.Index = context.Index;

        _state.SetKeywordContexts(context.KeywordContexts);
        _state.SetPunctuationContexts(context.PunctuationContexts);

        if (context.IgnoreTypeError)
        {
            _state.IgnoreTypeError = true;
        }

        if (context.ContainingNode != null &&
            context.ContainingNode.TryGetTarget(out Statement? containingNode))
        {
            _blockStack.Push(containingNode);
        }

        if (context.ContainingWithStatement != null &&
            context.ContainingWithStatement.TryGetTarget(out WithStatement? withStat))
        {
            _withStack.Push(withStat);
        }

        if (context.ContainingSection != null &&
            context.ContainingSection.TryGetTarget(out SectionStatement? section))
        {
            _section = section;
        }

        if (context.ContainingEventSection != null &&
            context.ContainingEventSection.TryGetTarget(out EventSection? eventSection))
        {
            _eventSection = eventSection;
        }
    }


    private static SyntaxTree ParseTree(SourceTextFile source, SyntaxTree? entryTree,
        SyntaxTreeParseContext? context)
    {
        Parser parser = new(source, entryTree);

        if (context != null)
        {
            parser.SetSyntaxTreeParseContext(context);
        }
        else if (source.Preprocessed?.GetDirectives()
                     .Any(d => d.DirectiveKind == DirectiveKinds.IgnoreTypeError) == true)
        {
            parser._state.IgnoreTypeError = true;
        }

        while (!parser.Eof())
        {
            parser.Next();

            if (parser.Eof())
            {
                break;
            }

            parser._tree.AddToRoot(parser.ParseStatement());
        }

        parser._tree.Finish();
        return parser._tree;
    }


    /// <summary>
    ///     解析源文件并返回一个语法树
    /// </summary>
    /// <param name="source">源文件</param>
    public static SyntaxTree Parse(SourceTextFile source)
    {
        return ParseTree(source, null, null);
    }


    private SourceNode GetCurrentNode()
    {
        Debug.Assert(_state.Current != null);
        return _state.Current;
    }


    private static SourceNode GetReportNode(SourceNode node)
    {
        if (node.Parent is SourceNode { IsMacroExpansion: true } expansion)
        {
            return expansion;
        }

        return node;
    }


    private static SyntaxPoint GetStartPoint(ITextRange range)
    {
        if (range is SourceNode sourceNode)
        {
            var reportNode = GetReportNode(sourceNode);
            return new SyntaxPoint(reportNode.Start, reportNode.StartLine);
        }

        return new SyntaxPoint(range.Start, range.StartLine);
    }


    private static SyntaxPoint GetEndPoint(ITextRange range)
    {
        if (range is SourceNode sourceNode)
        {
            var reportNode = GetReportNode(sourceNode);
            return new SyntaxPoint(reportNode.End, reportNode.EndLine);
        }

        return new SyntaxPoint(range.End, range.EndLine);
    }


    private SyntaxPoint GetCurrentStartPoint()
    {
        SourceNode node = GetCurrentReportNode();
        return new SyntaxPoint(node.Start, node.StartLine);
    }


    private SyntaxPoint GetCurrentEndPoint()
    {
        SourceNode node = GetCurrentReportNode();
        return new SyntaxPoint(node.End, node.EndLine);
    }


    private SourceNode GetCurrentReportNode()
    {
        SourceNode node = GetCurrentNode();
        return GetReportNode(node);
    }


    private bool HasPrecedingLinebreak()
    {
        return _state.HasPrecedingLinebreak();
    }

    private bool HasTrailingLinebreak()
    {
        return _state.HasTrailingLinebreak();
    }

    private bool IsLineEnd()
    {
        return HasTrailingLinebreak() || Eof();
    }


    private void Raise(DiagnosticDescriptor diagnostic, int start, int length, params object?[] args)
    {
        _diagnostics.Raise(diagnostic, SyntaxLocation.Create(_source.Uri, start, length), args);
    }


    private void Raise(DiagnosticDescriptor diagnostic, in TextSpan span, params object?[] args)
    {
        _diagnostics.Raise(diagnostic, span, args);
    }


    private void Raise(DiagnosticDescriptor diagnostic, ITextNode node, params object?[] args)
    {
        _diagnostics.Raise(diagnostic, node, args);
    }


    private TextSpan GetCurrentSpan()
    {
        // 宏展开内的节点映射到宏展开节点上
        if (_state.Expansion != null)
        {
            return _state.Expansion.Span;
        }

        // 如果在文本末尾，返回前一个区间
        if (Eof())
        {
            return _state.Last?.Span ?? TextSpan.StartOfFile(_source.Uri);
        }

        // 文件开头
        return _state.Current?.Span ?? TextSpan.StartOfFile(_source.Uri);
    }


    /// <summary>
    ///     报告一个诊断信息
    ///     <list type="number">
    ///         <item>如果在 #include 指令引入的节点中，报告在 #include 指令上</item>
    ///         <item>如果在宏展开列表中，报告在宏展开列表上</item>
    ///         <item>不满足上面的情况，报告在当前节点上</item>
    ///     </list>
    /// </summary>
    /// <param name="descriptor">报告的诊断信息</param>
    /// <param name="args">模板消息替换文本</param>
    private void Raise(DiagnosticDescriptor descriptor, params object?[] args)
    {
        Raise(descriptor, GetCurrentSpan(), args);
    }


    private void RaiseAt(DiagnosticDescriptor descriptor, int position, params object?[] args)
    {
        Raise(descriptor, position, 1, args);
    }


    private bool Eof()
    {
        return _state.Current?.IsEof == true;
    }

    private bool CurrentIs(SyntaxKinds kind)
    {
        return _state.Current?.IsNode(kind) == true;
    }

    private bool CurrentIsOneOf(params SyntaxKinds[] kinds)
    {
        return _state.Current?.IsOneOfNode(kinds) == true;
    }


    private SourceNode Next()
    {
        while (true)
        {
            _state.Last = _state.Current;

            // 如果在宏展开列表中，查找下一个节点
            if (_state.Expansion != null)
            {
                ++_state.ExpansionIndex;
                if (_state.ExpansionIndex < _state.Expansion.Count)
                {
                    return _state.Current = _state.Expansion[_state.ExpansionIndex];
                }

                _state.ClearExpansionState();
            }

            ++_state.Index;
            Debug.Assert(_state.Index < _length);

            SourceNode node = _nodes[_state.Index];

            // 进入宏展开列表
            if (!node.Is<MacroExpansion>(out MacroExpansion? expansion) &&
                !node.IsParserSkipped)
            {
                return _state.Current = node;
            }

            _state.ExpansionIndex = -1;
            _state.Expansion = expansion;
        }
    }


    private bool TryParse<T>(Func<T?> parser, [MaybeNullWhen(false)] out T res) where T : ITextNode
    {
        res = default;

        ParserState backup = _state;
        T? node = parser();

        if (node != null)
        {
            res = node;
            return true;
        }

        _state = backup;
        return false;
    }


    /// <summary>
    ///     尝试使用回调函数读取后续节点，并返回回调函数的返回值。
    ///     如果回调函数返回<see langword="null" />，将回溯节点位置。
    /// </summary>
    /// <param name="parser">解析器回调函数</param>
    /// <returns><paramref name="parser" />的返回值</returns>
    private T? TryParse<T>(Func<T?> parser) where T : class, ITextNode
    {
        ParserState backup = _state;
        T? node = parser();

        if (node != null)
        {
            return node;
        }

        _state = backup;
        return null;
    }


    private bool TryParse(SyntaxKinds[] kinds, [MaybeNullWhen(false)] out SourceNode res,
        bool reportDiagnostic = false, bool allowNewLine = false)
    {
        res = null;

        if (Eof())
        {
            return false;
        }

        ParserState backup = _state;
        SourceNode node = Next();

        if (node.IsOneOfNode(kinds))
        {
            if (!allowNewLine && node.HasPrecedingLinebreak)
            {
                if (reportDiagnostic)
                {
                    Raise(DiagnosticDescriptors.UnexpectedToken,
                        GetCurrentNode().End, GetCurrentNode().End + 1,
                        string.Join(" 或 ",
                            kinds.Select(SyntaxFacts.ConvertTokenToString)));
                }

                _state = backup;
                return false;
            }

            res = node;
            return true;
        }

        if (reportDiagnostic)
        {
            Raise(DiagnosticDescriptors.UnexpectedToken,
                node.Start, node.Start + 1,
                string.Join(" 或 ",
                    kinds.Select(SyntaxFacts.ConvertTokenToString)));
        }

        _state = backup;
        return false;
    }


    private bool TryParse(SyntaxKinds kind, [MaybeNullWhen(false)] out SourceNode res,
        bool reportDiagnostic = false, bool allowNewLine = false)
    {
        return TryParse([kind], out res, reportDiagnostic, allowNewLine);
    }


    private bool TryParse(SyntaxKinds kind, bool reportDiagnostic = false,
        bool allowNewLine = false)
    {
        return TryParse(kind, out _, reportDiagnostic, allowNewLine);
    }


    private void TryParse(SyntaxKinds kind, Action onSucceed,
        bool reportDiagnostic = false, bool allowNewLine = false)
    {
        if (TryParse(kind, reportDiagnostic, allowNewLine))
        {
            onSucceed();
        }
    }


    /// <summary>
    ///     解析下一个 Token，如果下一个节点不是 Token 节点，返回 <see langword="null" />。
    ///     此方法会调用 <see cref="Next" /> 方法，导致当前节点向前移动一个。
    /// </summary>
    private SyntaxToken? ParseToken()
    {
        SourceNode node = Next();

        if (node.IsTokenNode)
        {
            return NodeFactory.CreateSyntaxToken(node);
        }

        return null;
    }


    /// <summary>
    ///     将当前的 <see cref="SourceNode" /> 转换为 <see cref="SyntaxToken" /> 并返回。
    ///     此方法不会调用 <see cref="Next" /> 方法。
    /// </summary>
    private SyntaxToken GetToken()
    {
        SourceNode current = GetCurrentNode();
        return FinishNode(NodeFactory.CreateSyntaxToken(current),
            GetCurrentStartPoint(),
            current.Width,
            current.EndLine);
    }


    /// <summary>
    ///     如果当前节点是指定语法类型的Token，转换为<see cref="SyntaxToken" />并返回。
    /// </summary>
    /// <param name="kind">指定语法类型</param>
    /// <param name="stepNextIfSucceed">类型匹配时是否调用<see cref="Next" />方法</param>
    /// <param name="stepWhenTrailingNewline">
    ///     当<paramref name="stepNextIfSucceed" />是<see langword="true" />，并且当前节点后
    ///     带有换行符时，是否继续调用<see cref="Next" />方法前进Token
    /// </param>
    private SyntaxToken? OptionalCurrentToken(SyntaxKinds kind, bool stepNextIfSucceed = true,
        bool stepWhenTrailingNewline = false)
    {
        if (CurrentIs(kind))
        {
            SourceNode current = GetCurrentNode();
            if (stepNextIfSucceed && (!IsLineEnd() || stepWhenTrailingNewline))
            {
                Next();
            }

            return FinishNode(NodeFactory.CreateSyntaxToken(current), current);
        }

        return null;
    }


    /// <summary>
    ///     如果下一个是指定类型的Token，返回对应的<see cref="SyntaxToken" />，
    ///     如果不满足，不会前进到下一个Token。
    /// </summary>
    /// <param name="kind">指定的节点类型</param>
    /// <param name="allowNewLine">是否允许换行</param>
    private SyntaxToken? Optional(SyntaxKinds kind, bool allowNewLine = false)
    {
        if (!allowNewLine && IsLineEnd())
        {
            return null;
        }

        SyntaxToken? token = null;

        return TryParse(NextToken, out var res) ? res : token;

        SyntaxToken? NextToken()
        {
            SyntaxToken? tk = ParseToken();
            if (tk != null && tk.IsNode(kind))
            {
                return tk;
            }

            return null;
        }
    }


    private void CheckPrecedingLinebreak()
    {
        if (!HasPrecedingLinebreak())
        {
            RaiseAt(DiagnosticDescriptors.NeedLinebreak, GetCurrentSpan().Start);
        }
    }


    /// <summary>
    ///     期望下一个字符是标识符，如果不是，将返回<see cref="Identifier.Default" />，
    ///     并在当前节点的末尾部分报告错误
    /// </summary>
    private Identifier ExpectIdentifier(bool allowKeyword = false, bool reportDiagnostic = true)
    {
        if (TryParse(() =>
            {
                SourceNode n = Next();
                if (n.IsIdentifier || (n.IsKeywordToken() && allowKeyword))
                {
                    return ParseIdentifierName(allowKeyword);
                }

                return null;
            }, out var identifier))
        {
            return identifier;
        }

        if (reportDiagnostic)
        {
            RaiseAt(DiagnosticDescriptors.UnexpectedToken, GetCurrentSpan().Start, IdentifierName);
        }

        return Identifier.Default;
    }


    /// <summary>
    ///     如果下一个Token是指定类型中的一个，返回对应的<see cref="SyntaxToken" />，
    ///     如果不是，此方法不会前进到下一个Token。
    /// </summary>
    /// <param name="kinds">指定语法类型列表</param>
    /// <param name="allowNewLine">
    ///     是否允许换行，此参数为<see langword="false" />时，将在开始检查当前Token后是否换行，
    ///     如果换行了，将在当前文本位置报错，不会调用 <see cref="Next" /> 方法。
    /// </param>
    /// <param name="checkPrecedingLinebreak">
    ///     是否检查后一个Token的前方的换行符。如果此参数为<see langword="true" />，将在成功解析
    ///     后一个Token时，检查前方是否有换行符，如果没有，将在节点开头报错。
    /// </param>
    private SyntaxToken? Expect(SyntaxKinds[] kinds, bool allowNewLine = false,
        bool checkPrecedingLinebreak = false)
    {
        if (!allowNewLine && IsLineEnd())
        {
            RaiseAt(DiagnosticDescriptors.UnexpectedToken,
                GetCurrentSpan().End,
                string.Join(" 或 ",
                    kinds.Select(SyntaxFacts.ConvertTokenToString)));

            // Empty Token
            return null;
        }

        if (TryParse(NextToken, out var token))
        {
            if (checkPrecedingLinebreak)
            {
                CheckPrecedingLinebreak();
            }

            return token;
        }

        TextSpan span = GetCurrentSpan();

        RaiseAt(DiagnosticDescriptors.UnexpectedToken,
            span.End,
            string.Join(" 或 ",
                kinds.Select(SyntaxFacts.ConvertTokenToString)));

        return null;

        SyntaxToken? NextToken()
        {
            SyntaxToken? tk = ParseToken();
            if (tk != null && tk.IsOneOfNode(kinds))
            {
                return tk;
            }

            return null;
        }
    }


    /// <summary>
    ///     如果下一个Token是指定类型，返回对应的<see cref="SyntaxToken" />，
    ///     如果不是，此方法不会前进到下一个Token。
    /// </summary>
    /// <param name="kind">指定语法类型</param>
    /// <param name="allowNewLine">是否允许换行</param>
    /// <param name="checkPrecedingLinebreak">是否检查当前节点前是否带有换行符</param>
    /// <param name="reportDiagnostic">是否在不符合<paramref name="kind" />参数类型时报告错误</param>
    private SyntaxToken Expect(SyntaxKinds kind, bool allowNewLine = false,
        bool checkPrecedingLinebreak = false, bool reportDiagnostic = true)
    {
        if (!allowNewLine && IsLineEnd())
        {
            if (reportDiagnostic)
            {
                RaiseAt(DiagnosticDescriptors.UnexpectedToken,
                    GetCurrentSpan().End,
                    string.Join(" 或 ", SyntaxFacts.ConvertTokenToString(kind)));
            }

            // Empty Token
            return SyntaxToken.Default;
        }

        if (TryParse(NextToken, out var token))
        {
            if (checkPrecedingLinebreak)
            {
                CheckPrecedingLinebreak();
            }

            return token;
        }

        TextSpan span = GetCurrentSpan();

        if (reportDiagnostic)
        {
            RaiseAt(DiagnosticDescriptors.UnexpectedToken,
                span.End,
                SyntaxFacts.ConvertTokenToString(kind));
        }

        return SyntaxToken.Default;

        SyntaxToken? NextToken()
        {
            SyntaxToken? tk = ParseToken();
            if (tk != null && tk.IsNode(kind))
            {
                return tk;
            }

            return null;
        }
    }


    /// <summary>
    ///     期望读取一串连续的Token，期望顺序以<paramref name="tokens" />数组的顺序为准。
    ///     读取从当前节点开始，依次对后续Token调用<see cref="Expect(SyntaxKinds, bool, bool, bool)" />
    ///     方法，如果失败，不会调用<see cref="Next" />方法，而是继续尝试匹配下一个期望值。
    /// </summary>
    /// <param name="tokens">Token类型列表，顺序必须和期望顺序相同</param>
    /// <param name="checkPrecedingLinebreak">是否检查Token前的换行符</param>
    /// <param name="onParsed">期望判定成功时调用的回调函数，可以忽略</param>
    private void ExpectContinuousTokens(SyntaxKinds[] tokens,
        bool checkPrecedingLinebreak, Action<SyntaxToken>? onParsed = null)
    {
        Debug.Assert(tokens.Length > 0);
        SyntaxToken? token = ExpectCurrent(tokens[0], checkPrecedingLinebreak);
        if (token != null)
        {
            onParsed?.Invoke(token);
        }

        for (int i = 1; i < tokens.Length; i++)
        {
            token = Expect(tokens[i]);
            onParsed?.Invoke(token);
        }
    }


    /// <summary>
    ///     如果当前节点不是指定类型，返回<see langword="null" />并报告错误
    /// </summary>
    /// <param name="kind">指定语法类型</param>
    /// <param name="checkPrecedingLinebreak">是否检查当前节点前是否带有换行符</param>
    private SyntaxToken? ExpectCurrent(SyntaxKinds kind, bool checkPrecedingLinebreak = false)
    {
        if (checkPrecedingLinebreak)
        {
            CheckPrecedingLinebreak();
        }

        if (CurrentIs(kind))
        {
            return GetToken();
        }

        Raise(DiagnosticDescriptors.UnexpectedToken, SyntaxFacts.ConvertTokenToString(kind));
        return null;
    }


    private void AppendNodeFlag(AbstractTextNode targetNode)
    {
        if (_state.IsOptionImplicit)
        {
            targetNode.SetFlags(SyntaxNodeFlags.OptionImplicit);
        }

        if (_state.IsOptionGlobalVariables)
        {
            targetNode.SetFlags(SyntaxNodeFlags.OptionGlobalVariables);
        }

        if (_state.IsOnNextCaseEvent)
        {
            targetNode.SetFlags(SyntaxNodeFlags.OnNextCaseEvent);
        }

        if (_state.IgnoreTypeError)
        {
            targetNode.SetFlags(SyntaxNodeFlags.IgnoreTypeError);
        }
    }


    private static void AppendTrivia(SourceNode source, AbstractTextNode targetNode)
    {
        targetNode.SetLeadingComment(source.GetLeadingComment());
        targetNode.SetTrailingComment(source.GetTrailingComment());
    }


    private void UpdateContaining<T>(T node) where T : SyntaxNode
    {
        if (_withStack.TryPeek(out WithStatement? withStat))
        {
            node.Update(withStat);
        }

        if (_eventSection != null)
        {
            node.Update(_eventSection);
        }

        if (_section != null)
        {
            node.Update(_section);
        }
    }


    private static void UpdateDeclaration<T>(T node) where T : Declaration
    {
        node.SetLeadingComment(node.DeclareKeywordToken.GetLeadingComment());
    }


    private T FinishNode<T>(T node, SourceNode? source = null) where T : AbstractTextNode
    {
        source ??= _state.Current;
        if (source != null)
        {
            AppendNodeFlag(node);
            AppendTrivia(source, node);
            SourceNode reportNode = GetReportNode(source);
            node.Update(reportNode, source.Text);
        }

        node.SetUri(_source.Uri);

        if (node.Is<SyntaxNode>(out SyntaxNode? synNode))
        {
            UpdateContaining(synNode);
        }

        if (node.Is<Declaration>(out Declaration? decl))
        {
            UpdateDeclaration(decl);
        }

        return node;
    }


    private T FinishNode<T>(T node, SyntaxPoint startPoint, int? length = null, int? endLine = null)
        where T : AbstractTextNode
    {
        if (node.Is<SyntaxNode>(out SyntaxNode? synNode))
        {
            UpdateContaining(synNode);
        }

        if (node.Is<Declaration>(out Declaration? decl))
        {
            UpdateDeclaration(decl);
        }

        SourceNode currentReportNode = GetCurrentReportNode();
        int len = length ?? currentReportNode.End - startPoint.Position - 
            (currentReportNode.IsEof ? 1 : 0) /* Lexer读取的Eof带有1宽度，此处需要减去，否则此处len会比字符串宽度大 */;
        int edl = endLine ?? currentReportNode.EndLine;
        node.SetUri(_source.Uri);
        node.Update(startPoint.Position, len,
            _source.Substring(startPoint.Position, len));
        node.UpdateLine(startPoint.Line, edl);
        AppendNodeFlag(node);
        return node;
    }


    private T FinishNode<T>(T node, SyntaxPoint start, SyntaxPoint end)
        where T : AbstractTextNode
    {
        return FinishNode(node, start, end.Position - start.Position, end.Line);
    }


    private void SkipLine()
    {
        while (!IsLineEnd())
        {
            Next();
        }
    }

    private struct ParserState
    {
        // Option
        public bool IsOptionImplicit { get; set; }

        public bool IsOptionGlobalVariables { get; set; }


        // OnNextCase Event
        public bool IsOnNextCaseEvent { get; set; }

        // 宏展开
        public MacroExpansion? Expansion { get; set; }
        public int ExpansionIndex { get; set; }

        public void ClearExpansionState()
        {
            Expansion = null;
            ExpansionIndex = -1;
        }

        // 上一个节点
        public SourceNode? Last { get; set; }

        // 当前节点
        public SourceNode? Current { get; set; }

        public int Index { get; set; }

        public readonly bool HasPrecedingLinebreak()
        {
            return Current?.HasPrecedingLinebreak == true;
        }

        public readonly bool HasTrailingLinebreak()
        {
            return Expansion?.HasTrailingLinebreak ?? Current?.HasTrailingLinebreak == true;
        }


        // Context

        public KeywordContexts KeywordContexts { get; private set; }

        public PunctuationContexts PunctuationContexts { get; private set; }


        public readonly bool GetKeywordContexts(KeywordContexts keywordContext)
        {
            return (KeywordContexts & keywordContext) != 0;
        }

        public void SetKeywordContexts(KeywordContexts keywordContext)
        {
            KeywordContexts = keywordContext;
        }

        public void SetPunctuationContexts(PunctuationContexts punctuationContexts)
        {
            PunctuationContexts = punctuationContexts;
        }

        // ignore-type-error
        public bool IgnoreTypeError { get; set; }
    }


    private class SyntaxTreeParseContext
    {
        public bool IsOptionImplicit { get; init; }

        public bool IsOptionGlobalVariables { get; init; }

        public bool IgnoreTypeError { get; init; }

        public WeakReference<Statement>? ContainingNode { get; init; }

        public int Index { get; init; }

        public KeywordContexts KeywordContexts { get; init; }

        public PunctuationContexts PunctuationContexts { get; init; }

        public WeakReference<WithStatement>? ContainingWithStatement { get; init; }

        public WeakReference<EventSection>? ContainingEventSection { get; init; }

        public WeakReference<SectionStatement>? ContainingSection { get; init; }
    }
}